local inSpecialZone = function()
  local zoneText = GetRealZoneText()
  local specialZones = InstanceTimerDB.boomcounter.specialZones
  return type(specialZones) == 'table' and specialZones[zoneText] == 1
end

local inInstance = function(ignoreType)
  local isIn, type = IsInInstance()

  -- 返回值1周年服为true， 乌龟服为1
  return (isIn and (ignoreType == true or type == "party" or InstanceTimerDB.boomcounter.lograid == true)) or inSpecialZone()
end

local addLog = function(ttime)
  if not ttime then ttime = time() end
  table.insert(InstanceTimerDB.logs, { t = ttime })
end

local colors = {
  { 0.8, 0,   0, 1 }, -- 0
  { 0.8, 0.7, 0, 1 },
  { 0.6, 0.8, 0, 1 },
  { 0.4, 0.8, 0, 1 },
  { 0.2, 0.8, 0, 1 },
  { 0,   0.8, 0, 1 },
}
local getColor = function(i)
  return colors[i + 1]
end

local frame = CreateFrame("Frame", "InstanceTimerBoomCounterFrame", InstanceTimerFrame)
local font = GameFontNormal:GetFont()
frame:SetWidth(32)
frame:SetHeight(InstanceTimer.height)
frame.timesleftText = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
frame.timesleftText:SetPoint("CENTER", frame, "CENTER")
frame.timesleftText:SetFont(font, InstanceTimer.fontsize1)

frame.inInstance = inInstance

local maxPerDay = 30 -- 未确认
local maxPerHour = 5 -- 已确认， 修改数量需要配合其他位置修改
local timesleft

local getTimesLeft = function()
  local oldValue = timesleft
  timesleft = maxPerHour
  local i = table.getn(InstanceTimerDB.logs)
  while i > 0 do
    if time() - InstanceTimerDB.logs[i].t >= 3600 then
      break
    end
    timesleft = timesleft - 1
    i = i - 1
  end
  if timesleft < 0 then
    timesleft = 0
  end

  if oldValue ~= timesleft then
    frame.updateVisible(true)
  end
  return timesleft
end

frame.getTimesLeft = getTimesLeft

frame:RegisterEvent("PLAYER_ENTERING_WORLD")
frame:RegisterEvent("CHAT_MSG_SYSTEM")
local defaults = {
  autolog = true,
  lograid = false,
  specialZones = {
    ["暴风城地牢"] = 1,
  },
  hiddenlimit = 5,
  showprogressalways = false
}

local updateTextAndColor = function()
  getTimesLeft()
  frame.timesleftText:SetText(timesleft)
  frame.timesleftText:SetTextColor(unpack(getColor(timesleft)))
end

frame.onLoad = function()
  if not InstanceTimerDB.logs then
    InstanceTimerDB.logs = {}
  end
  if not InstanceTimerDB.boomcounter then
    InstanceTimerDB.boomcounter = {}
  end
  for k, v in pairs(defaults) do
    if InstanceTimerDB.boomcounter[k] == nil then
      InstanceTimerDB.boomcounter[k] = v
    end
  end

  getTimesLeft()
end

local onEnteringWorld = function()
  local stat = inInstance()
  if InstanceTimerDB.lastStat == nil or InstanceTimerDB.lastStat ~= stat then
    if stat == true then
      if not InstanceTimerDB.logs then
        InstanceTimerDB.logs = {}
      end

      -- 进本
      -- v0.3起需要判断InstanceTimerDB.reseted == true 才记录
      if InstanceTimerDB.boomcounter.autolog and InstanceTimerDB.reseted == true then
        InstanceTimerDB.reseted = nil
        addLog()
      else
        if table.getn(InstanceTimerDB.logs) == 0 then
          addLog()
        else
          local ttime = time()
          -- 弹框询问是否一个新副本
          StaticPopupDialogs["NEW_INSTANCE_CHECK"] = {
            text = "检测到进入副本，是新的副本吗？",
            button1 = "是的",
            button2 = "不是",
            OnAccept = function()
              -- 是，记录
              addLog(ttime)
            end,
            OnCancel = function()
              -- 否，刷新时间
              InstanceTimer.boomcounter.addOrCoverLog(ttime)
            end,
            timeout = 0,
            whileDead = true,
            hideOnEscape = false,
            preferredIndex = 3
          }
          -- 显示弹窗
          StaticPopup_Show("NEW_INSTANCE_CHECK")
        end
      end
      InstanceTimer.trigger("IN_INSTANCE")
    else
      -- 出本（首次使用可能不准确）
      InstanceTimer.trigger("OUT_INSTANCE")
    end
  end
  InstanceTimerDB.lastStat = stat
  updateTextAndColor()
end

frame:SetScript("OnEvent", function()
  if event == "PLAYER_ENTERING_WORLD" then
    onEnteringWorld()
    -- addLog()
  elseif event == "CHAT_MSG_SYSTEM" then
    if string.match(arg1, "已被重置。$") then
      -- 副本已重置（未进本）
      InstanceTimerDB.reseted = true
    end
  end
end)

local lineColors = {
  { 1,     0.58,  0.824, 1 },
  { 0.69,  0.58,  1,     1 },
  { 0.322, 0.741, 1,     1 },
  { 0.475, 0.973, 0.467, 1 },
  { 1,     0.984, 0.58,  1 },
  -- { 0.937, 0.573, 0.753, 1 },
  -- { 0.673, 0.61,  0.937, 1 },
  -- { 0.439, 0.741, 0.596, 1 },
  -- { 0.245, 0.818, 0.561, 1 },
  -- { 0.145, 0.994, 0.561, 1 },
}
local lines = {}
for i = 1, 5 do
  local line = CreateFrame("Frame", nil, frame)
  line:SetPoint("LEFT", frame, "RIGHT", 5, 0)
  line:SetHeight(InstanceTimerFrame:GetHeight())
  line.bg = line:CreateTexture(nil, "BACKGROUND")
  line.bg:SetTexture(unpack(lineColors[i]))
  line.bg:SetAllPoints(line)
  line:SetFrameLevel(3 + i)
  line:Hide()
  table.insert(lines, line)
end

local lineWrapper = CreateFrame("Frame", nil, frame)
lineWrapper:SetPoint("LEFT", frame, "RIGHT", 5, 0)
lineWrapper:SetHeight(InstanceTimerFrame:GetHeight())
lineWrapper:SetWidth(100)
lineWrapper.bg = lineWrapper:CreateTexture(nil, "BACKGROUND")
lineWrapper.bg:SetTexture(0, 0, 0, 0.5)
lineWrapper.bg:SetAllPoints(lineWrapper)
lineWrapper:Hide()
-- TestTextFrame:ClearAllPoints();TestTextFrame:SetPoint("LEFT", InstanceTimer.boomcounter, "RIGHT", 5, 0)
local textFrame = CreateFrame("Frame", "TestTextFrame", frame)
textFrame:SetPoint("LEFT", frame, "RIGHT", 5, 0)
textFrame:SetWidth(lineWrapper:GetWidth())
textFrame:SetHeight(lineWrapper:GetHeight())
textFrame:SetFrameLevel(maxPerHour + 4)
textFrame.text = textFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
textFrame.text:SetFont(font, InstanceTimer.fontsize2)
textFrame.text:SetTextColor(1, 1, 1, 1)
textFrame.text:SetPoint("RIGHT", textFrame, "RIGHT", -5, 0)
textFrame:Hide()

local linesTriggerFrame = CreateFrame("Frame", "InstanceTimerLinesTriggerFrame", frame)
linesTriggerFrame:SetWidth(10)
linesTriggerFrame:SetHeight(frame:GetHeight())
linesTriggerFrame:SetPoint("RIGHT", frame, "RIGHT", 5, 0)
linesTriggerFrame:EnableMouse(true)

local showLines = function()
  for i, line in ipairs(lines) do
    line:Hide()
  end
  local count = 0
  local logsLen = table.getn(InstanceTimerDB.logs)
  local index = logsLen
  local tt = time()

  while index > 0 do
    if tt - InstanceTimerDB.logs[index].t >= 3600 then
      break
    end
    count = count + 1
    index = index - 1

    if count == maxPerHour then break end
  end

  if count == 0 and not InstanceTimerDB.boomcounter.showprogressalways then
    lineWrapper:Hide()
    textFrame:Hide()
    return
  end

  lineWrapper:Show()
  textFrame:Show()

  for i = 1, count do
    local diff = tt - InstanceTimerDB.logs[logsLen - i + 1].t
    local diffr = 3600 - diff

    local s = ""
    if diffr > 60 then
      s = "" .. math.floor(diffr / 60) .. "m"
    else
      s = "" .. diffr .. "s"
    end

    local lineWidth = math.floor(diff / 3600 * 100)
    if lineWidth == 0 then
      lineWidth = 0.01
    end
    lines[count - i + 1]:SetWidth(lineWidth)
    -- lines[count - i + 1]:SetWidth(100)
    -- lines[count - i + 1].text:SetText(s)
    lines[count - i + 1]:Show()

    if i == count then
      textFrame.text:SetText(s)
    end
  end
end

local hideLines = function()
  lineWrapper:Hide()
  textFrame:Hide()
  for k, v in ipairs(lines) do
    v:Hide()
  end
end
frame.showLines = showLines
frame.hideLines = hideLines

linesTriggerFrame:SetScript("OnEnter", function()
  if InstanceTimerDB.boomcounter.showprogressalways then
    return
  end
  showLines()
end)
linesTriggerFrame:SetScript("OnLeave", function()
  if InstanceTimerDB.boomcounter.showprogressalways then
    return
  end
  hideLines()
end)
frame.buttons = { linesTriggerFrame }

local lasttime
frame:SetScript("OnUpdate", function()
  if not lasttime or time() > lasttime then
    updateTextAndColor()
    if timesleft >= 5 then
      textFrame.text:SetText("")
    end
    if frame:GetAlpha() ~= 0 and InstanceTimerDB.boomcounter.showprogressalways then
      showLines()
    end

    lasttime = time()
  end
end)


local updateVisible = function(updateFrameSize)
  local visible = frame:GetAlpha() ~= 0
  if visible and (not InstanceTimerDB.showcounter or (InstanceTimerDB.boomcounter.hiddenlimit and timesleft > InstanceTimerDB.boomcounter.hiddenlimit)) then
    -- frame:Hide()
    frame:SetAlpha(0)
    frame:SetWidth(0.001)
    frame.timesleftText:Hide()
    if updateFrameSize then InstanceTimerFrame.updateFramesWidthAndPoint() end
  elseif not visible and InstanceTimerDB.showcounter and (not InstanceTimerDB.boomcounter.hiddenlimit or timesleft <= InstanceTimerDB.boomcounter.hiddenlimit) then
    -- frame:Show()
    frame:SetAlpha(1)
    frame:SetWidth(32)
    frame.timesleftText:Show()
    frame:Show()
    if updateFrameSize then InstanceTimerFrame.updateFramesWidthAndPoint() end
  end
end
frame.updateVisible = updateVisible

InstanceTimer.register("OPTIONS_CHANGED", frame)
frame.OPTIONS_CHANGED = function(key, value)
  if key == "showcounter" or key == "boomcounter.hiddenlimit" then
    -- if value then
    --   frame:Show()
    -- else
    --   frame:Hide()
    -- end
    updateVisible(true)
  elseif key == "boomcounter.showprogressalways" then
    if value == true and frame:IsVisible() then
      showLines()
    else
      hideLines()
    end
  end
end

InstanceTimer.boomcounter = frame
InstanceTimer.addFrame(frame)

frame.addLog = function()
  addLog()
  updateTextAndColor()
end
frame.removeLastLog = function()
  table.remove(InstanceTimerDB.logs)
  updateTextAndColor()
end
frame.clearLogs = function()
  InstanceTimerDB.logs = {}
  updateTextAndColor()
end
frame.coverLog = function()
  if table.getn(InstanceTimerDB.logs) > 1 then
    local log = table.remove(InstanceTimerDB.logs)
    InstanceTimerDB.logs[table.getn(InstanceTimerDB.logs)].t = log.t
    updateTextAndColor()
  end
end
frame.addOrCoverLog = function(ttime)
  if not ttime then ttime = time() end
  if table.getn(InstanceTimerDB.logs) == 0 then
    addLog(ttime)
  else
    InstanceTimerDB.logs[table.getn(InstanceTimerDB.logs)].t = ttime
  end
  updateTextAndColor()
end
frame.addSpecialZone = function(zoneName)
  if not InstanceTimerDB.boomcounter.specialZones then
    InstanceTimerDB.boomcounter.specialZones = {}
  end
  InstanceTimerDB.boomcounter.specialZones[zoneName] = 1
end
frame.removeSpecialZone = function(zoneName)
  if type(InstanceTimerDB.boomcounter.specialZones) == 'table' and InstanceTimerDB.boomcounter.specialZones[zoneName] then
    InstanceTimerDB.boomcounter.specialZones[zoneName] = nil
  end
end
frame.showSpecialZones = function()
  if type(InstanceTimerDB.boomcounter.specialZones) == 'table' then
    for k, v in pairs(InstanceTimerDB.boomcounter.specialZones) do
      print(k)
    end
  end
end
frame.clearSpecialZones = function()
  InstanceTimerDB.boomcounter.specialZones = {}
end
